package com.demo.druid.component.datasource;

import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.demo.druid.component.datasource.annotation.DataSourceKey;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.aspectj.AnnotationTransactionAspect;
import org.springframework.transaction.jta.JtaTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author wangjianhua
 * @Description
 * @date 2021/9/1/001 14:09
 **/
@Configuration
public class DataSourceConfigure {

    @Value("${spring.profiles.active}")
    private String active;


    @Bean(name = "master")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.druid.master")
    public DataSource master(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "slave1")
    @ConfigurationProperties(prefix = "spring.datasource.druid.slave1")
    public DataSource slave1(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "slave2")
    @ConfigurationProperties(prefix = "spring.datasource.druid.slave2")
    public DataSource slave2(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "slave3")
    @ConfigurationProperties(prefix = "spring.datasource.druid.slave3")
    public DataSource slave3(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean("dynamicDataSource")
    public DataSource dynamicDataSource(){
        DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
        Map<Object,Object> dataSourceMap = new HashMap<>(8);
        dataSourceMap.put(DataSourceKey.master.name(),master());
        dataSourceMap.put(DataSourceKey.slave1.name(),slave1());
        dataSourceMap.put(DataSourceKey.slave2.name(),slave2());
        dataSourceMap.put(DataSourceKey.slave3.name(),slave3());
        //设置动态数据源 默认数据源
        dynamicRoutingDataSource.setDefaultTargetDataSource(master());
        //设置数据源组
        dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);
        //把所有数据源加入数据源列表
        DynamicDataSourceContextHolder.dataSourceKeys.addAll(dataSourceMap.keySet());
        //把所有从数据源加入到从数据源列表 这样方便在切换数据源时轮询
        DynamicDataSourceContextHolder.slaveDataSourceKeys.addAll(dataSourceMap.keySet());
        DynamicDataSourceContextHolder.slaveDataSourceKeys.remove(DataSourceKey.master.name());
        return dynamicRoutingDataSource;
    }

    /**
     * 原生的sqlSessionFactoryBean和mybatis-plus会有冲突 mybatis-plus需要使用MybatisSqlSessionFactoryBean
     * @return 这里使用原生的SqlSessionFactoryBean 放弃使用mybatis plus 太坑爹了
     * @throws Exception
     */
    @Bean
    public SqlSessionFactory sqlSessionFactoryBean() throws Exception{
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dynamicDataSource());
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/**/*.xml"));
        //  动态切换sql打印 如果不是开发环境或者本地环境 不打印sql
        if("dev".equals(active)){
            org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
            configuration.setLogImpl(StdOutImpl.class);
            sqlSessionFactoryBean.setConfiguration(configuration);
        }
        return sqlSessionFactoryBean.getObject();

    }

    /**
     * 以下注释是为了事务传播行为的正确配置
     * DataSourceTransactionManager天然不支持多数据源 因此 可以考虑jta方案 以后可能会有实现
     */
     @Bean(name = "platformTransactionManager")
     public PlatformTransactionManager transactionManager(){
         DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
         dataSourceTransactionManager.setDataSource(dynamicDataSource());
//       dataSourceTransactionManager.setValidateExistingTransaction(false);
         return dataSourceTransactionManager;
     }
}
